Skip to content

10 中间件

在前面的文章中,我们学会了创建Agent、定义工具、管理记忆、流式输出等等。但在实际项目中,你经常会遇到一些"横切关注点"的问题——比如:

  • 每次模型调用前都要记日志
  • 工具调用失败时要自动重试
  • 对话太长时要自动摘要
  • 涉及敏感操作时要人工确认
  • 输出中包含个人信息时要脱敏

这些功能如果写在业务代码里,会很乱很杂。中间件就是来解决这类问题的——它让你在Agent执行的各个关键节点插入自定义逻辑,而不用改动核心代码。

一、什么是中间件

中间件(Middleware)是一种拦截器机制,可以在Agent执行的特定时机插入自定义逻辑。打个比方,如果Agent的执行流程是一条流水线,中间件就像是流水线上的"检查站",你可以在每个检查站做日志记录、数据校验、格式转换等操作。

中间件最常见的用途:

  • 日志和调试:记录Agent的输入输出,方便排查问题
  • 提示词转换:动态修改系统提示词,注入用户上下文
  • 工具选择:根据场景动态选择可用工具
  • 重试和回退:模型调用失败时自动重试或切换备用模型
  • 安全防护:PII脱敏、内容审核、速率限制
  • 人机交互:敏感操作需要人工确认

二、添加中间件

使用create_agentmiddleware参数传入中间件列表:

python
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],
    middleware=[
        SummarizationMiddleware(...),
        HumanInTheLoopMiddleware(...),
    ],
)

中间件按照列表顺序执行,排在前面的先执行。

三、内置中间件

LangChain提供了一系列开箱即用的内置中间件,覆盖了最常见的场景。

3.1 消息摘要(SummarizationMiddleware)

当对话越来越长时,token消耗会急剧增加。摘要中间件可以在对话超过一定长度时自动压缩历史消息,保留关键信息的同时减少token占用。

python
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],
    middleware=[
        SummarizationMiddleware(
            max_tokens=4000,  # 对话超过4000 token时触发摘要
        ),
    ],
)

3.2 人机交互(HumanInTheLoopMiddleware)

有些操作比较敏感,比如发邮件、删除数据、修改配置等,你希望在执行前让人工确认一下。人机交互中间件可以在指定工具调用前暂停,等待用户确认后再继续。

python
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[send_email, delete_file],
    middleware=[
        HumanInTheLoopMiddleware(
            interrupt_on={
                "send_email": True,    # 调用send_email前暂停
                "delete_file": True,   # 调用delete_file前暂停
            }
        ),
    ],
)

当Agent要调用这些工具时,会暂停执行并返回一个中断信息,用户确认后再用Command恢复执行。

3.3 PII脱敏(PIIMiddleware)

如果Agent的输出可能包含用户的个人信息(邮箱、电话、身份证号等),可以用PII中间件自动检测并脱敏。

python
from langchain.agents import create_agent
from langchain.agents.middleware import PIIMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],
    middleware=[
        PIIMiddleware(
            "email",           # 脱敏邮箱
            strategy="redact", # 策略:替换为[REDACTED]
        ),
    ],
)

支持的PII类型:emailphonecredit_cardssn(美国社会安全号)等。

3.4 工具重试(ToolRetryMiddleware)

工具调用有时候会因为网络问题、超时等原因失败。重试中间件可以自动重试失败的工具调用。

python
from langchain.agents import create_agent
from langchain.agents.middleware import ToolRetryMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[call_api],
    middleware=[
        ToolRetryMiddleware(
            max_retries=3,     # 最多重试3次
            retry_delay=1.0,   # 每次重试间隔1秒
        ),
    ],
)

3.5 模型回退(ModelFallbackMiddleware)

当主模型不可用时(比如API超时、限流),自动切换到备用模型,保证服务不中断。

python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelFallbackMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],
    middleware=[
        ModelFallbackMiddleware(
            fallback_models=["openai:gpt-5.4", "anthropic:claude-sonnet-4-6"],
        ),
    ],
)

3.6 调用次数限制(ModelCallLimitMiddleware)

防止Agent陷入死循环,限制模型调用的最大次数。

python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],
    middleware=[
        ModelCallLimitMiddleware(max_calls=10),  # 最多调用10次模型
    ],
)

3.7 LLM工具选择(LLMToolSelectorMiddleware)

当工具很多时,把所有工具都传给模型会浪费token,也可能影响工具选择的准确性。这个中间件可以让LLM根据用户的问题,动态选择最相关的工具子集。

python
from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolSelectorMiddleware

agent = create_agent(
    model="deepseek-v4-flash",
    tools=[...],  # 注册所有工具
    middleware=[
        LLMToolSelectorMiddleware(
            max_tools=5,  # 每次最多选择5个工具
        ),
    ],
)

四、中间件的执行顺序

当中间件有多个时,它们的执行顺序是有讲究的:

before类Hookbefore_agentbefore_model):按列表顺序从前往后执行

after类Hookafter_modelafter_agent):按列表顺序从后往前执行(反序)

wrap类Hookwrap_model_callwrap_tool_call):像洋葱一样层层嵌套

举个例子:

python
agent = create_agent(
    model="deepseek-v4-flash",
    middleware=[middleware1, middleware2, middleware3],
    tools=[...],
)

执行顺序:

middleware1.before_agent()
  middleware2.before_agent()
    middleware3.before_agent()
    
    Agent循环开始:
    middleware1.before_model()
      middleware2.before_model()
        middleware3.before_model()
        
        middleware1.wrap_model_call() → 
          middleware2.wrap_model_call() → 
            middleware3.wrap_model_call() → 调用模型
        
        middleware3.after_model()
      middleware2.after_model()
    middleware1.after_model()
    Agent循环结束
    
    middleware3.after_agent()
  middleware2.after_agent()
middleware1.after_agent()

简单记:before从前往后,after从后往前,wrap像洋葱一样嵌套

五、在LangGraph工作流中使用中间件

中间件不是独立的运行时,它运行在create_agent返回的LangGraph图内部。你可以把带中间件的Agent作为节点嵌入到更大的LangGraph工作流中:

python
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.graph import START, StateGraph

# 创建带中间件的Agent
email_agent = create_agent(
    model="deepseek-v4-flash",
    tools=[read_email, send_email],
    middleware=[HumanInTheLoopMiddleware(interrupt_on={"send_email": True})],
)

# 把Agent作为节点嵌入到更大的工作流中
graph = (
    StateGraph(AgentState)
    .add_node("classify", classify_node)
    .add_node("email_agent", email_agent)
    .add_edge(START, "classify")
    .add_conditional_edges("classify", route)
    .compile()
)

中间件的所有功能(人机交互、摘要、PII脱敏等)都会跟着Agent节点一起工作。

六、总结

中间件是LangChain中扩展Agent能力的核心机制:

  • 中间件可以在Agent执行的各个关键节点插入自定义逻辑
  • 内置中间件覆盖了最常见的场景:摘要、人机交互、PII脱敏、重试、回退、调用限制、工具选择
  • 通过create_agentmiddleware参数添加,支持多个中间件组合使用
  • 执行顺序:before从前往后,after从后往前,wrap嵌套

在下一篇文章中,我们将学习如何编写自定义中间件,实现更灵活的Agent控制逻辑。